/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package beans;

import beans.exceptions.NonexistentEntityException;
import entities.Book;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import entities.Author;
import java.util.ArrayList;
import java.util.Collection;
import entities.Orderr;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;


@ManagedBean(name="bookDao")
@ApplicationScoped
public class BookDAO {

    public BookDAO() {
        emf = Persistence.createEntityManagerFactory("BookstorePU");
    }
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Book book) {
        if (book.getAuthors() == null) {
            book.setAuthors(new ArrayList<Author>());
        }
        if (book.getOrders() == null) {
            book.setOrders(new ArrayList<Orderr>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Collection<Author> attachedAuthors = new ArrayList<Author>();
            for (Author authorsAuthorToAttach : book.getAuthors()) {
                authorsAuthorToAttach = em.getReference(authorsAuthorToAttach.getClass(), authorsAuthorToAttach.getId());
                attachedAuthors.add(authorsAuthorToAttach);
            }
            book.setAuthors(attachedAuthors);
            Collection<Orderr> attachedOrders = new ArrayList<Orderr>();
            for (Orderr ordersOrderrToAttach : book.getOrders()) {
                ordersOrderrToAttach = em.getReference(ordersOrderrToAttach.getClass(), ordersOrderrToAttach.getId());
                attachedOrders.add(ordersOrderrToAttach);
            }
            book.setOrders(attachedOrders);
            em.persist(book);
            for (Author authorsAuthor : book.getAuthors()) {
                authorsAuthor.getBooks().add(book);
                authorsAuthor = em.merge(authorsAuthor);
            }
            for (Orderr ordersOrderr : book.getOrders()) {
                ordersOrderr.getBooks().add(book);
                ordersOrderr = em.merge(ordersOrderr);
            }
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Book book) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Book persistentBook = em.find(Book.class, book.getId());
            Collection<Author> authorsOld = persistentBook.getAuthors();
            Collection<Author> authorsNew = book.getAuthors();
            Collection<Orderr> ordersOld = persistentBook.getOrders();
            Collection<Orderr> ordersNew = book.getOrders();
            Collection<Author> attachedAuthorsNew = new ArrayList<Author>();
            for (Author authorsNewAuthorToAttach : authorsNew) {
                authorsNewAuthorToAttach = em.getReference(authorsNewAuthorToAttach.getClass(), authorsNewAuthorToAttach.getId());
                attachedAuthorsNew.add(authorsNewAuthorToAttach);
            }
            authorsNew = attachedAuthorsNew;
            book.setAuthors(authorsNew);
            Collection<Orderr> attachedOrdersNew = new ArrayList<Orderr>();
            for (Orderr ordersNewOrderrToAttach : ordersNew) {
                ordersNewOrderrToAttach = em.getReference(ordersNewOrderrToAttach.getClass(), ordersNewOrderrToAttach.getId());
                attachedOrdersNew.add(ordersNewOrderrToAttach);
            }
            ordersNew = attachedOrdersNew;
            book.setOrders(ordersNew);
            book = em.merge(book);
            for (Author authorsOldAuthor : authorsOld) {
                if (!authorsNew.contains(authorsOldAuthor)) {
                    authorsOldAuthor.getBooks().remove(book);
                    authorsOldAuthor = em.merge(authorsOldAuthor);
                }
            }
            for (Author authorsNewAuthor : authorsNew) {
                if (!authorsOld.contains(authorsNewAuthor)) {
                    authorsNewAuthor.getBooks().add(book);
                    authorsNewAuthor = em.merge(authorsNewAuthor);
                }
            }
            for (Orderr ordersOldOrderr : ordersOld) {
                if (!ordersNew.contains(ordersOldOrderr)) {
                    ordersOldOrderr.getBooks().remove(book);
                    ordersOldOrderr = em.merge(ordersOldOrderr);
                }
            }
            for (Orderr ordersNewOrderr : ordersNew) {
                if (!ordersOld.contains(ordersNewOrderr)) {
                    ordersNewOrderr.getBooks().add(book);
                    ordersNewOrderr = em.merge(ordersNewOrderr);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Long id = book.getId();
                if (findBook(id) == null) {
                    throw new NonexistentEntityException("The book with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Long id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Book book;
            try {
                book = em.getReference(Book.class, id);
                book.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The book with id " + id + " no longer exists.", enfe);
            }
            Collection<Author> authors = book.getAuthors();
            for (Author authorsAuthor : authors) {
                authorsAuthor.getBooks().remove(book);
                authorsAuthor = em.merge(authorsAuthor);
            }
            Collection<Orderr> orders = book.getOrders();
            for (Orderr ordersOrderr : orders) {
                ordersOrderr.getBooks().remove(book);
                ordersOrderr = em.merge(ordersOrderr);
            }
            em.remove(book);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public Collection<Book> getAllBooks() {
        return getAllBooks(true, -1, -1);
    }

    public Collection<Book> getAllBooks(int maxResults, int firstResult) {
        return getAllBooks(false, maxResults, firstResult);
    }

    private Collection<Book> getAllBooks(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            Query q = em.createNamedQuery("getAllBooks");
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            //System.out.println("RESULTS:");
            //System.out.println(q.getResultList());

            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Book findBook(Long id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Book.class, id);
        } finally {
            em.close();
        }
    }

    public int getBookCount() {
        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select count(o) from Book as o");
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }

}
